package com.tanhua.server.service;

import com.github.tobato.fastdfs.domain.conn.FdfsWebServer;
import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import com.tanhua.commons.template.OssTemplate;
import com.tanhua.domain.db.UserInfo;
import com.tanhua.domain.mongo.Video;
import com.tanhua.domain.vo.PageResult;
import com.tanhua.domain.vo.VideoVO;
import com.tanhua.dubbo.api.FollowUserApi;
import com.tanhua.dubbo.api.UserInfoApi;
import com.tanhua.dubbo.api.VideoApi;
import com.tanhua.server.interceptor.UserHolder;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author liuyp
 * @date 2021/02/02
 */
@Service
public class VideoService {
    @Autowired
    private OssTemplate ossTemplate;
    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    @Autowired
    private FastFileStorageClient fastFileStorageClient;

    @Autowired
    private FdfsWebServer fdfsWebServer;

    @Reference
    private VideoApi videoApi;
    @Reference
    private UserInfoApi userInfoApi;
    @Reference
    private FollowUserApi followUserApi;

    @Autowired
    private VideoMQService mqService;

    // @CacheEvict(cacheNames = "video_list", allEntries = true)
    public ResponseEntity saveVideo(MultipartFile videoFile, MultipartFile videoImage) throws IOException {

        //1. 把图片存储到阿里云OSS
        String imagePath = ossTemplate.upload(videoImage.getOriginalFilename(), videoImage.getInputStream());

        //2. 把视频存储到FastDFS
        //   xxxx.mp4
        String videoName = videoFile.getOriginalFilename();
        //   mp4
        String suffix = videoName.substring(videoName.lastIndexOf(".")+1);
        StorePath storePath = fastFileStorageClient.uploadFile(videoFile.getInputStream(), videoFile.getSize(), suffix, null);
        //   group1/M00/00/00/wKj3oGAYrqiAAhQlAABonuLw4M4949.jpg
        String fullPath = storePath.getFullPath();
        String videoPath = fdfsWebServer.getWebServerUrl() + fullPath;

        //3. 把视频信息存储到MongoDB
        Video video = new Video();
        video.setUserId(UserHolder.getUserId());
        video.setText("帅哥");
        video.setPicUrl(imagePath);
        video.setVideoUrl(videoPath);

        String videoId = videoApi.save(video);

        //发送消息，供大数据推荐系统使用
        mqService.saveVideoMessage(videoId);

        return ResponseEntity.ok(null);
    }

    /**
     * 页码1，查询10条，key=1_10
     */
    // @Cacheable(cacheNames = "video_list", key = "#page + '_' + #pagesize")
    public PageResult<VideoVO> findVideoList(int page, int pagesize) {
        //1. 查询视频列表：优先从Redis里找推荐的视频；如果找不到再从MongoDB里查找
        PageResult<Video> pageResult = findVideoFromRedis(page, pagesize);
        if (pageResult == null) {
            pageResult = videoApi.findVideoList(page, pagesize);
        }

        //2. 转换成VideoVO
        List<Video> videoList = pageResult.getItems();
        List<VideoVO> voList = new ArrayList<>();
        for (Video video : videoList) {
            VideoVO vo = new VideoVO();

            //封装视频发布者的信息
            UserInfo userInfo = userInfoApi.findById(video.getUserId());
            vo.setUserId(userInfo.getId());
            vo.setAvatar(userInfo.getAvatar());
            vo.setNickname(userInfo.getNickname());

            //封装视频信息
            vo.setId(video.getId().toHexString());
            vo.setCover(video.getPicUrl());
            vo.setVideoUrl(video.getVideoUrl());
            vo.setSignature(video.getText());

            vo.setLikeCount(0);
            vo.setCommentCount(0);

            //当前用户对此视频是否点赞了
            vo.setHasLiked(0);
            //当前用户对此视频作者是否关注了
            Boolean hasFocus = redisTemplate.hasKey("video_focus_" + UserHolder.getUserId() + "_" + video.getUserId());
            vo.setHasFocus(hasFocus?1:0);

            voList.add(vo);
        }

        //3. 构造返回值
        PageResult<VideoVO> voPageResult = new PageResult<>();
        BeanUtils.copyProperties(pageResult, voPageResult);
        voPageResult.setItems(voList);
        return voPageResult;
    }

    private PageResult<Video> findVideoFromRedis(int page, int pagesize) {
        //1. 从Redis里查找数据 100049,100016,100002,100023,100050,23,20,17,100074,100056
        String vidStr = redisTemplate.opsForValue().get("QUANZI_VIDEO_RECOMMEND_" + UserHolder.getUserId());
        if (vidStr == null) {
            return null;
        }

        //2. 计算总数量
        String[] vidArray = vidStr.split(",");
        int count = vidArray.length;

        //3. 计算分了多少页
        int pages = (int) Math.ceil(count * 1.0 / pagesize);

        //4. 查询视频列表
        if (page <= pages) {
            int start = (page - 1) * pagesize;
            int end = start + pagesize;
            if (end > count) {
                end = count;
            }

            List<Long> vidList = new ArrayList<>();
            for (int i = start; i < end; i++) {
                long vid = Long.parseLong(vidArray[i]);
                vidList.add(vid);
            }

            List<Video> videoList = videoApi.findVideoByVids(vidList);

            return new PageResult<>(count, pagesize, pages, page, videoList);
        }
        return new PageResult<>();
    }

    public ResponseEntity followUser(Long targetUserId) {
        followUserApi.followUser(UserHolder.getUserId(), targetUserId);

        //把这个关注操作记录到Redis里
        redisTemplate.opsForValue().set("video_focus_"+UserHolder.getUserId()+"_"+targetUserId, "1");

        return ResponseEntity.ok(null);
    }

    public ResponseEntity unfollowUser(Long targetUserId) {
        //调用API，取消关注
        followUserApi.unfollowUser(UserHolder.getUserId(), targetUserId);

        //删除Redis里的关注记录
        redisTemplate.delete("video_focus_" + UserHolder.getUserId() + "_" + targetUserId);

        return ResponseEntity.ok(null);
    }
}
